<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件传输</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
        }

        body {
            background-color: #f5f5f7;
            color: #1d1d1d;
            line-height: 1.5;
            padding: 16px;
            -webkit-user-select: none;
            /* Chrome/Safari */
            -moz-user-select: none;
            /* Firefox */
            -ms-user-select: none;
            /* IE/Edge */
            user-select: none;
            /* Standard syntax */
        }

        .container {
            max-width: 500px;
            margin: 0 auto;
            background-color: #ffffff;
            border-radius: 18px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            padding: 16px;
            margin-top: 20px;
        }

        h1 {
            font-size: 22px;
            font-weight: 600;
            margin-bottom: 20px;
            color: #000;
            text-align: center;
            /* 将标题居中 */
        }

        .section {
            margin-bottom: 30px;
        }

        .section-title {
            font-size: 18px;
            font-weight: 600;
            margin-bottom: 16px;
            color: #333;
        }

        .upload-group,
        .download-group {
            background-color: #f9f9f9;
            border-radius: 12px;
            padding: 16px;
            margin-bottom: 24px;
        }

        .file-input-container {
            position: relative;
            margin-bottom: 16px;
        }

        .file-input-label {
            display: inline-block;
            width: 100%;
            padding: 12px;
            background-color: #007aff;
            color: white;
            /* border-radius: 12px; */
            font-size: 16px;
            font-weight: 500;
            cursor: pointer;
            text-align: center;
            transition: background-color 0.3s;
        }

        .file-input-label:hover {
            background-color: #0066cc;
        }

        .file-input {
            position: absolute;
            width: 0.1px;
            height: 0.1px;
            opacity: 0;
            overflow: hidden;
            z-index: -1;
        }

        .btn {
            width: 100%;
            padding: 14px;
            /* border-radius: 12px; */
            font-size: 16px;
            font-weight: 500;
            cursor: pointer;
            transition: background-color 0.3s;
            border: none;
            text-align: center;
            margin-top: 10px;
        }

        .btn-upload {
            background-color: #007aff;
            color: white;
        }

        .btn-upload:hover {
            background-color: #0066cc;
        }

        .btn-upload:disabled {
            background-color: #888;
            cursor: not-allowed;
        }

        .btn-download {
            background-color: #34c759;
            color: white;
        }

        .btn-download:hover {
            background-color: #2d6d2c;
        }

        .progress-container {
            margin-top: 16px;
            margin-bottom: 16px;
            display: none;
            /* 默认隐藏进度容器 */
        }

        .progress-bar {
            height: 10px;
            background-color: #e0e0e0;
            /* border-radius: 5px; */
            overflow: hidden;
        }

        #progress {
            height: 100%;
            background-color: #007aff;
            width: 0%;
            transition: width 0.3s;
        }

        #uploadStatus,
        #fileInfo {
            margin-top: 10px;
            font-size: 14px;
            color: #666;
        }

        #successMessage {
            margin-top: 10px;
            font-size: 14px;
            color: #28a745;
            display: none;
        }

        #downloadInfo {
            margin-top: 10px;
            font-size: 14px;
            color: #666;
        }

        .segment-control {
            display: inline-flex;
            border-radius: 5px;
            overflow: hidden;
            background-color: #e5e5e5;
            border: 1px solid #ccc;
            height: 40px;
            width: 100%;
            /* 修改为 100% */
        }

        .segment {
            flex: 1;
            text-align: center;
            line-height: 40px;
            cursor: pointer;
            transition: background-color 0.3s;
            font-size: 14px;
            color: #666;
            border-radius: 5px;
        }

        .segment.active {
            background-color: white;
            color: #000;
            font-weight: 500;
            box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
        }

        .segment:first-child {
            border-top-left-radius: 5px;
            border-bottom-left-radius: 5px;
        }

        .segment:last-child {
            border-top-right-radius: 5px;
            border-bottom-right-radius: 5px;
        }

        #downloadProgress {
            transition: width 0.3s ease-out;
        }
    </style>
</head>

<body>
    <div class="container">
        <h1>文件传输</h1>

        <div class="upload-group">
            <h2 class="section-title">上传文件</h2>
            <div class="progress-container" id="uploadProgressContainer">
                <div class="progress-bar">
                    <div id="progress"></div>
                </div>
                <p id="uploadStatus"></p>
            </div>
            <div class="file-input-container">
                <label for="fileInput" class="file-input-label">选取文件</label>
                <input type="file" id="fileInput" name="file" multiple class="file-input">
            </div>
            <p id="selectedFileInfo"></p>
            <button id="uploadButton" class="btn btn-upload" onclick="uploadFiles()">开始上传</button>
            <p id="successMessage"></p>
        </div>

        <div class="download-group">
            <h2 class="section-title">下载文件</h2>
            <p id="downloadtip">下载哪里的文件数据</p>
            <div class="segment-control">
                <div class="segment active" data-source="downloads">Downloads</div>
                <div class="segment" data-source="uploads">Uploads</div>
            </div>
            <button id="downloadOneByOneButton" class="btn btn-download" onclick="downloadAllFiles()">下载所有文件</button>
            <p id="downloadInfo"></p>

            <!-- 添加下载进度容器 -->
            <div class="progress-container" id="downloadProgressContainer" style="display: none; margin-top: 16px;">
                <div class="progress-bar">
                    <div id="downloadProgress" style="height: 100%; background-color: #34c759; width: 0%;"></div>
                </div>
                <p id="downloadStatus" style="margin-top: 8px; font-size: 14px;"></p>
            </div>

        </div>
    </div>

    <script>

        document.querySelectorAll('.segment').forEach(segment => {
            segment.addEventListener('click', function () {
                document.querySelectorAll('.segment').forEach(s => {
                    s.classList.remove('active');
                });
                this.classList.add('active');
            });
        });

        let totalFiles = 0;
        let startTime = 0;

        document.addEventListener('contextmenu', function (e) {
            e.preventDefault();
        });
        document.getElementById('fileInput').addEventListener('change', function () {
            const fileCount = this.files.length;
            const selectedFileInfo = document.getElementById('selectedFileInfo');
            if (fileCount > 0) {
                selectedFileInfo.textContent = `已选取 ${fileCount} 个文件`;
            } else {
                selectedFileInfo.textContent = '';
            }
            const successMessage = document.getElementById('successMessage');
            successMessage.style.display = 'none';
        });

        function uploadFiles() {
            const selectedFileInfo = document.getElementById('selectedFileInfo');
            selectedFileInfo.textContent = '';

            const fileInput = document.getElementById('fileInput');
            const files = fileInput.files;
            totalFiles = files.length;

            if (files.length === 0) {
                console.log('No files selected');
                alert('请选择文件');
                return;
            }

            const formData = new FormData();
            let totalFileSize = 0;
            for (let i = 0; i < files.length; i++) {
                formData.append('file', files[i]);
                formData.append('filename', files[i].name);
                totalFileSize += files[i].size; // 累加文件大小
            }

            const uploadButton = document.getElementById('uploadButton');
            uploadButton.disabled = true;
            fileInput.disabled = true;
            uploadButton.textContent = '上传中...';

            const uploadStatus = document.getElementById('uploadStatus');
            const progress = document.getElementById('progress');
            const successMessage = document.getElementById('successMessage');
            const uploadProgressContainer = document.getElementById('uploadProgressContainer');

            uploadProgressContainer.style.display = 'block'; // 显示进度容器
            uploadStatus.textContent = '上传开始';

            startTime = new Date().getTime(); // 记录开始时间

            const xhr = new XMLHttpRequest();
            xhr.open('POST', `http://${window.location.hostname}:3000/upload`, true);

            xhr.upload.addEventListener('progress', function (event) {
                if (event.lengthComputable) {
                    const currentTime = new Date().getTime();
                    const elapsedTime = (currentTime - startTime) / 1000; // 转换为秒

                    const percentage = Math.round((event.loaded / event.total) * 100);
                    const loadedMB = (event.loaded / (1024 * 1024)).toFixed(2); // 转换为MB
                    const speedMBps = elapsedTime > 0 ? (loadedMB / elapsedTime).toFixed(2) : '0.00'; // 计算上传速度 (MB/s)

                    const remainingSize = event.total - event.loaded; // 剩余字节数
                    const estimatedTime = speedMBps > 0 ? (remainingSize / (speedMBps * 1024 * 1024)).toFixed(2) : '0.00'; // 预计剩余时间(秒)

                    progress.style.width = `${percentage}%`;
                    uploadStatus.textContent = `上传中: ${percentage}%`;

                    if (elapsedTime > 0) {
                        uploadStatus.textContent = `上传中: ${percentage}% 速度: ${speedMBps} MB/s\n预计剩余: ${formatTime(parseFloat(estimatedTime))}`;
                    }
                }
            }, false);

            xhr.onload = function () {
                if (xhr.status === 200) {
                    uploadStatus.textContent = '上传完成';

                    const endTime = new Date().getTime();
                    const elapsedTime = (endTime - startTime) / 1000; // 耗时（秒）
                    const totalMB = (totalFileSize / (1024 * 1024)).toFixed(2); // 总文件大小（MB）

                    successMessage.textContent = `成功上传 ${files.length} 个文件，耗时 ${formatTime(elapsedTime)}，共计 ${formatSize(totalFileSize)}`;
                    successMessage.style.display = 'block';

                    setTimeout(() => {
                        uploadButton.disabled = false;
                        uploadButton.textContent = '开始上传';
                        fileInput.value = '';
                        progress.style.width = '0%';
                        uploadStatus.textContent = '';
                        uploadProgressContainer.style.display = 'none'; // 隐藏进度容器
                    }, 2000);
                } else {
                    uploadStatus.textContent = '上传失败';
                    uploadButton.disabled = false;
                    uploadButton.textContent = '开始上传';
                }
            };

            xhr.onerror = function () {
                uploadStatus.textContent = '上传失败';
                uploadButton.disabled = false;
                uploadButton.textContent = '开始上传';
            };

            xhr.send(formData);
        }

        async function downloadAllFiles() {
            const downloadOneByOneButton = document.getElementById('downloadOneByOneButton');
            downloadOneByOneButton.disabled = true;

            const downloadInfo = document.getElementById('downloadInfo');
            const downloadProgressContainer = document.getElementById('downloadProgressContainer');
            const downloadProgress = document.getElementById('downloadProgress');
            const downloadStatus = document.getElementById('downloadStatus');

            downloadInfo.textContent = '正在获取文件列表...';
            downloadProgressContainer.style.display = 'block';

            // 获取当前选中的source
            const activeSegment = document.querySelector('.segment.active');
            const source = activeSegment.getAttribute('data-source');

            try {
                const fileRequest = await fetch(`http://${window.location.hostname}:3000/get-file-list?source=${source}`);
                const files = await fileRequest.json();
                const totalFiles = files.length;

                if (totalFiles === 0) {
                    downloadInfo.textContent = '没有文件可下载';
                    downloadProgressContainer.style.display = 'none';
                    setTimeout(() => {
                        downloadOneByOneButton.disabled = false;
                    }, 2000);
                    return;
                }

                let totalSize = 0;
                for (const file of files) {
                    totalSize += file.size || 0;
                }

                downloadInfo.textContent = `本次下载 ${totalFiles} 个文件，共计 ${formatSize(totalSize)}`;

                // 创建下载管理器
                const downloadManager = {
                    files: files,
                    currentIndex: 0,
                    downloadedBytes: 0,
                    startTime: new Date().getTime(),
                    totalSize: totalSize,

                    downloadNext: async function () {
                        if (this.currentIndex >= this.files.length) {
                            // 所有文件下载完成
                            downloadStatus.textContent = '所有文件下载完成';
                            downloadInfo.textContent = `下载完成，共 ${this.files.length} 个文件`;

                            setTimeout(() => {
                                downloadProgressContainer.style.display = 'none';
                                downloadOneByOneButton.disabled = false;
                            }, 2000);
                            return;
                        }

                        const file = this.files[this.currentIndex];
                        this.currentIndex++;

                        // 显示当前下载的文件信息
                        downloadStatus.textContent = `正在下载 ${this.currentIndex}/${totalFiles}: ${file.name}...`;

                        // 下载单个文件
                        await this.downloadFile(file, source);

                        // 继续下载下一个文件
                        this.downloadNext();
                    },

                    downloadFile: async function (file, source) {

                        // 判断文件大小 - 超过500MB使用大文件下载方法
                        if (file.size > 500 * 1024 * 1024) {
                            await downloadLargeFile(file, source);
                        } else {
                            // 使用原有方法下载小文件
                            return new Promise((resolve, reject) => {
                                // 重置lastLoaded为0，确保每个文件都从0开始计算
                                this.lastLoaded = 0;  // 添加这行关键修复

                                const xhr = new XMLHttpRequest();
                                const url = `http://${window.location.hostname}:3000/download-file?name=${encodeURIComponent(file.name)}&category=${encodeURIComponent(file.category)}&source=${source}`;

                                xhr.open('GET', url, true);
                                xhr.responseType = 'blob';

                                // 记录文件下载开始时间
                                const fileStartTime = new Date().getTime();

                                xhr.onprogress = (event) => {
                                    if (event.lengthComputable) {
                                        // 更新单个文件进度
                                        const filePercent = Math.round((event.loaded / event.total) * 100);

                                        // 更新总体进度
                                        this.downloadedBytes += event.loaded - (this.lastLoaded || 0);
                                        this.lastLoaded = event.loaded;
                                        const totalPercent = (this.downloadedBytes / this.totalSize) * 100;
                                        // 计算下载速度
                                        const currentTime = new Date().getTime();
                                        const elapsedTime = (currentTime - this.startTime) / 1000;
                                        const speedMBps = elapsedTime > 0 ? (this.downloadedBytes / (1024 * 1024) / elapsedTime).toFixed(2) : '0.00';

                                        // 更新进度条
                                        downloadProgress.style.width = `${totalPercent}%`;

                                        // 更新状态文本
                                        downloadStatus.textContent = `(${this.currentIndex}/${totalFiles}) ${file.name}: ${filePercent}% | 速度: ${speedMBps} MB/s`;
                                    }

                                    manageMemory();
                                };

                                xhr.onload = () => {
                                    if (xhr.status === 200) {
                                        const blob = xhr.response;
                                        const url = window.URL.createObjectURL(blob);
                                        const a = document.createElement('a');
                                        a.href = url;
                                        a.download = file.name;
                                        document.body.appendChild(a);
                                        a.click();
                                        window.URL.revokeObjectURL(url);
                                        document.body.removeChild(a);

                                        this.lastLoaded = 0;
                                        resolve();
                                    } else {
                                        reject(new Error(`下载失败 (${xhr.status})`));
                                    }
                                };

                                xhr.onerror = () => {
                                    downloadStatus.textContent = `下载失败: ${file.name}`;
                                    downloadStatus.style.color = '#ff3b30';
                                    reject(new Error('下载失败'));
                                };

                                xhr.send();
                            });
                        }
                    },


                };

                // 开始下载
                downloadManager.downloadNext();

            } catch (error) {
                console.error('下载失败:', error);
                downloadStatus.textContent = '下载失败: ' + error.message;
                downloadInfo.textContent = '下载失败';

                setTimeout(() => {
                    downloadProgressContainer.style.display = 'none';
                    downloadOneByOneButton.disabled = false;
                }, 5000);
            }
        }

        // 定期清理已下载块
        function manageMemory() {
            // 每下载100MB清理一次已合并的块
            if (downloadManager.downloaded - lastMemoryClean > 100 * 1024 * 1024) {
                // 清理已合并的块
                for (let i = 0; i < downloadManager.chunks.length; i++) {
                    if (downloadManager.chunks[i].merged) {
                        downloadManager.chunks[i].blob = null;
                        downloadManager.chunks.splice(i, 1);
                        i--;
                    }
                }
                lastMemoryClean = downloadManager.downloaded;
            }
        }

        async function downloadLargeFile(file, source) {
            // 获取文件信息
            const infoUrl = `http://${window.location.hostname}:3000/file-info?name=${encodeURIComponent(file.name)}&category=${encodeURIComponent(file.category)}&source=${source}`;
            const infoResponse = await fetch(infoUrl);
            const fileInfo = await infoResponse.json();

            const fileSize = fileInfo.size;
            const chunkSize = fileInfo.chunkSize; // 服务器推荐的块大小

            // 创建下载管理器
            const downloadManager = {
                fileSize: fileSize,
                downloaded: 0,
                chunks: [],
                activeRequests: [],

                // 下载文件块
                downloadChunk: async function (start, end) {
                    const rangeHeader = `bytes=${start}-${end}`;

                    const response = await fetch(
                        `http://${window.location.hostname}:3000/download-file?name=${encodeURIComponent(file.name)}&category=${encodeURIComponent(file.category)}&source=${source}`,
                        {
                            headers: { Range: rangeHeader }
                        }
                    );

                    if (response.status === 206) {
                        const blob = await response.blob();
                        this.chunks.push({
                            start: start,
                            end: end,
                            blob: blob
                        });
                        this.downloaded += blob.size;

                        // 更新进度
                        const percent = (this.downloaded / this.fileSize) * 100;
                        downloadProgress.style.width = `${percent}%`;
                        downloadStatus.textContent = `下载中: ${percent.toFixed(1)}%`;

                        return true;
                    }
                    return false;
                },

                // 合并文件块并保存
                mergeAndSave: function () {
                    // 按顺序排序文件块
                    this.chunks.sort((a, b) => a.start - b.start);

                    // 创建完整Blob
                    const fullBlob = new Blob(this.chunks.map(chunk => chunk.blob),
                        { type: 'application/octet-stream' });

                    // 创建下载链接
                    const url = URL.createObjectURL(fullBlob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = file.name;
                    document.body.appendChild(a);
                    a.click();

                    // 清理
                    setTimeout(() => {
                        document.body.removeChild(a);
                        URL.revokeObjectURL(url);
                    }, 100);
                },

                // 并行下载文件
                download: async function () {
                    const numChunks = Math.ceil(fileSize / chunkSize);

                    for (let i = 0; i < numChunks; i++) {
                        const start = i * chunkSize;
                        const end = Math.min((i + 1) * chunkSize - 1, fileSize - 1);

                        // 并行下载（限制并发数）
                        this.activeRequests.push(this.downloadChunk(start, end));

                        // 控制并发数量
                        if (this.activeRequests.length >= 4) {
                            await Promise.race(this.activeRequests);
                            // 移除已完成请求
                            this.activeRequests = this.activeRequests.filter(req => !req.isCompleted);
                        }
                    }

                    // 等待所有请求完成
                    await Promise.all(this.activeRequests);
                    this.mergeAndSave();
                }
            };

            // 开始下载
            await downloadManager.download();
        }

        // 在 formatSize 函数后添加
        function calculateSpeed(loadedBytes, startTime) {
            const currentTime = new Date().getTime();
            const elapsedSeconds = (currentTime - startTime) / 1000;

            if (elapsedSeconds > 0) {
                return (loadedBytes / (1024 * 1024) / elapsedSeconds).toFixed(2);
            }
            return '0.00';
        }

        // 添加 formatTime 和 formatSize 函数
        function formatTime(seconds) {
            const hours = Math.floor(seconds / 3600);
            const minutes = Math.floor((seconds % 3600) / 60);
            const secs = Math.floor(seconds % 60);
            if (hours > 0) {
                return `${hours}小时${minutes}分钟${secs}秒`;
            } else if (minutes > 0) {
                return `${minutes}分钟${secs}秒`;
            } else {
                return `${secs}秒`;
            }
        }

        function formatSize(bytes) {
            if (bytes >= 1073741824) { // >=1GB
                return (bytes / 1073741824).toFixed(2) + ' GB';
            } else if (bytes >= 1048576) { // >=1MB
                return (bytes / 1048576).toFixed(2) + ' MB';
            } else if (bytes >= 1024) { // >=1KB
                return (bytes / 1024).toFixed(2) + ' KB';
            } else {
                return bytes + ' B';
            }
        }
    </script>
</body>

</html>